/***
 * @Description: 本文件主要定义和IP地址有关的内容，包括数据结构的C语言文件
 * @Author: Liverpool
 * @Date: 2024-04-22 01:47:16
 * @LastEditTime: 2024-04-22 01:47:54
 * @LastEditors: Liverpool
 */
#include "ipaddr.h"
/***
 * @description: 对IP地址进行初始设置
 * @Author: Liverpool
 * @Date: 2024-04-25 01:06:47
 * @return {*}
 * @param {D_IP_ADDR} *ip ip地址指针
 */
void ip_addr_set_any(D_IP_ADDR *ip)
{
    ip->type = IP_ADDR_V4;
    ip->q_addr = 0;
}
/***
 * @description: 判断IP地址是否为空
 * @Author: Liverpool
 * @Date: 2024-10-02 03:19:33
 * @return {*}
 * @param {D_IP_ADDR} *ip ip地址指针
 */
int ip_addr_is_any(D_IP_ADDR *ip)
{
    return ip->q_addr == 0;
}
/***
 * @description: 根据点分十进制的字符串转化为IP地址的数据格式
 * @Author: Liverpool
 * @Date: 2024-05-05 14:54:18
 * @return {*} 在转化过程中出现的错误
 * @param {D_IP_ADDR} *dest 转化完成后存储的目标地址内存
 * @param {char} *str 需要转化的字符串
 */
net_err_t ipaddr_from_str(D_IP_ADDR *dest, const char *str)
{
    if (!dest || !str)
        return NET_ERR_PARAM;
    dest->type = IP_ADDR_V4;
    dest->q_addr = 0;
    // 根据字符串转化为IP地址
    uint8_t *p = dest->a_addr;
    uint8_t sub_addr = 0;
    char c;
    while ((c = *str++) != '\0')
    {
        if ((c >= '0') && (c <= '9'))
        {
            sub_addr = sub_addr * 10 + (c - '0');
        }
        else if (c == '.')
        {
            *p++ = sub_addr;
            sub_addr = 0;
        }
        else
        {
            return NET_ERR_PARAM;
        }
    }
    *p = sub_addr;
    return NET_ERR_OK;
}

/***
 * @description: 对IP地址进行copy
 * @Author: Liverpool
 * @Date: 2024-05-05 20:33:56
 * @return {*}
 * @param {D_IP_ADDR} *dest 需要copy的目标地址
 * @param {D_IP_ADDR} *src  copy对象的源地址
 */
void ipaddr_copy(D_IP_ADDR *dest, const D_IP_ADDR *src)
{
    if (!dest || !src)
        return;
    dest->type = src->type;
    dest->q_addr = src->q_addr;
}
/***
 * @description: 得到空IP地址的内存
 * @Author: Liverpool
 * @Date: 2024-05-05 20:36:29
 * @return {*} 空IP的内存地址
 */
D_IP_ADDR *ipaddr_get_any(void)
{
    static const D_IP_ADDR ipaddr_any = {.type = IP_ADDR_V4, .q_addr = 0};
    return (D_IP_ADDR *)&ipaddr_any;
}

/***
 * @description: 用于判断两个IP地址是否相同
 * @Author: Liverpool
 * @Date: 2024-06-05 01:20:50
 * @return {*} 1 表示IP地址相同 0 表示IP地址不同
 * @param {D_IP_ADDR} *ip1 需要判断的IP地址1
 * @param {D_IP_ADDR} *ip2 需要判断的IP地址2
 */
int ipaddr_is_equal(const D_IP_ADDR *ip1, const D_IP_ADDR *ip2)
{
    return ip1->q_addr == ip2->q_addr;
}

/***
 * @description: 把IP地址写入到buf中
 * @Author: Liverpool
 * @Date: 2024-06-07 01:55:34
 * @return {*}
 * @param {D_IP_ADDR} *ip 需要写入的IP地址
 * @param {uint8_t} *in_buf 需要进行写入的buf内存地址
 */
void ipaddr_to_buf(const D_IP_ADDR *ip, uint8_t *in_buf)
{
    *(uint32_t *)in_buf = ip->q_addr;
}

/***
 * @description: 从字节数组buf中解析IP地址
 * @Author: Liverpool
 * @Date: 2024-06-17 00:12:31
 * @return {*}
 * @param {D_IP_ADDR} *ip 需要写入的IP结构体内存地址
 * @param {uint8_t} *buf 保存IP数据的数组
 */
void ipaddr_from_buf(D_IP_ADDR *ip, uint8_t *buf)
{
    ip->type = IP_ADDR_V4;
    ip->q_addr = *(uint32_t *)buf;
}

/***
 * @description: 判断当前IP地址是否为本地广播
 * @Author: Liverpool
 * @Date: 2024-06-24 02:55:15
 * @return {*} 1:是 0:不是
 * @param {D_IP_ADDR} *ipaddr 要查询的IP地址
 */
int ipaddr_is_local_broadcast(const D_IP_ADDR *ipaddr)
{
    return ipaddr->q_addr == 0xFFFFFFFF;
}

/***
 * @description: 根据IP地址和子网掩码查找处于当前网络下的主机号
 * @Author: Liverpool
 * @Date: 2024-06-24 03:09:23
 * @return {*} 返回主机号
 * @param {D_IP_ADDR} *ipaddr 查询的IP地址
 * @param {D_IP_ADDR} *netmask 其对应的子网掩码
 */
D_IP_ADDR ipaddr_get_host(const D_IP_ADDR *ipaddr, const D_IP_ADDR *netmask)
{
    D_IP_ADDR hostid;
    hostid.q_addr = ipaddr->q_addr & (~netmask->q_addr);
    return hostid;
}

/***
 * @description: 根据IP地址和子网掩码来来获取当前网络下的网络号
 * @Author: Liverpool
 * @Date: 2024-07-10 13:17:33
 * @return {*} 返回网络号
 * @param {D_IP_ADDR} *ipaddr 查询的IP地址
 * @param {D_IP_ADDR} *netmask 其对应的子网掩码
 */
D_IP_ADDR ipaddr_get_net(const D_IP_ADDR *ipaddr, const D_IP_ADDR *netmask)
{
    D_IP_ADDR netid;
    netid.q_addr = ipaddr->q_addr & (netmask->q_addr);
    return netid;
}

/***
 * @description: 判断当前的IP地址是否为定向广播
 * @Author: Liverpool
 * @Date: 2024-06-24 02:55:34
 * @return {*} 1:是 0:不是
 * @param {D_IP_ADDR} *ipaddr 要查询的IP地址
 * @param {D_IP_ADDR} *netmask 其匹配的子网掩码
 */
int ipaddr_is_direct_broadcast(const D_IP_ADDR *ipaddr, const D_IP_ADDR *netmask)
{
    D_IP_ADDR hostid = ipaddr_get_host(ipaddr, netmask);
    return hostid.q_addr == (0xFFFFFFFF & (~netmask->q_addr));
}

/***
 * @description: 判断目的地址和源地址是否匹配
 * @Author: Liverpool
 * @Date: 2024-07-10 13:27:08
 * @return {*} 1:匹配 0:不匹配
 * @param {D_IP_ADDR} *dest 目的地址
 * @param {D_IP_ADDR} *src 源地址
 * @param {D_IP_ADDR} *netmask 源地址的子网掩码
 */
int ipaddr_is_match(const D_IP_ADDR *dest, const D_IP_ADDR *src, const D_IP_ADDR *netmask)
{
    D_IP_ADDR src_net = ipaddr_get_net(src, netmask);
    D_IP_ADDR dest_net = ipaddr_get_net(dest, netmask);
    // 1.判断是否是本地广播地址
    if (ipaddr_is_local_broadcast(dest))
    {
        return 1;
    }
    // 2.判断是否是定向广播地址,并且需要判断源地址和目的地址之间的网络是否相同
    if (ipaddr_is_direct_broadcast(dest, netmask) && ipaddr_is_equal(&src_net, &dest_net))
    {
        return 1;
    }
    // 3.判断目的地址和源地址是否相等
    return ipaddr_is_equal(dest, src);
}